package com.e3.core.utils;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLStreamHandlerFactory;
import java.util.Hashtable;
import java.util.jar.JarFile;

import sun.misc.Resource;
import sun.misc.URLClassPath;

public class ClassUtils {

	private static Hashtable<String, Class<?>> primitiveTypes = new Hashtable<String, Class<?>>();

	private static Hashtable<String, Class<?>> primitiveToWrapper = new Hashtable<String, Class<?>>();

	private static Hashtable<String, Object> primitiveToReturnValues = new Hashtable<String, Object>();
	
	private static JarClassLoader jarClassLoader = null;
	
	private static JarFile jarFile = null;

	static {
		primitiveTypes.put("int", int.class);
		primitiveTypes.put("char", char.class);
		primitiveTypes.put("boolean", boolean.class);
		primitiveTypes.put("float", float.class);
		primitiveTypes.put("double", double.class);
		primitiveTypes.put("void", void.class);
		primitiveTypes.put("long", long.class);
		primitiveTypes.put("byte", byte.class);

		primitiveToWrapper.put("int", Integer.class);
		primitiveToWrapper.put("char", Character.class);
		primitiveToWrapper.put("boolean", Boolean.class);
		primitiveToWrapper.put("float", Float.class);
		primitiveToWrapper.put("double", Double.class);
		primitiveToWrapper.put("long", Long.class);
		primitiveToWrapper.put("byte", Byte.class);

		primitiveToReturnValues.put("int", Integer.MIN_VALUE);
		primitiveToReturnValues.put("char", new Character('#'));
		primitiveToReturnValues.put("boolean", false);
		primitiveToReturnValues.put("float", Float.MIN_VALUE);
		primitiveToReturnValues.put("double", Double.MIN_VALUE);
		primitiveToReturnValues.put("long", Long.MIN_VALUE);
		primitiveToReturnValues.put("byte", Byte.MIN_VALUE);
	}

	public static Class<?> getPrimitiveClassByName(String name) {
		return primitiveTypes.get(name);
	}

	public static Class<?> getPrimitiveWrapperByName(String name) {
		return primitiveToWrapper.get(name);
	}

	public static Object getPrimitiveReturnValue(String name) {
		return primitiveToReturnValues.get(name);
	}

	public static Class<?>[] getClassesByNames(String[] classNames)
			throws ClassNotFoundException {
		ClassLoader loder = Thread.currentThread().getContextClassLoader();
		Class<?>[] classes = new Class[classNames.length];
		for (int i = 0; i < classNames.length; i++) {
			String className = classNames[i];
			Class<?> clazz = getPrimitiveClassByName(className);
			if (clazz == null) {
				clazz = Class.forName(className, false, loder);
			}
			classes[i] = clazz;
		}
		return classes;
	}

	public static Class<?> getClassesByName(String className)	throws ClassNotFoundException {
		String[] classNames = new String[1];
		classNames[0] = className;
		Class<?>[] classes = getClassesByNames(classNames);
		return classes[0];
	}

	public static boolean isSameURL(Class<?> clazz1, Class<?> clazz2) {
		URL clazz1URL = FileUtils.getJarUrlOfClass(clazz1);
		URL clazz2URL = FileUtils.getJarUrlOfClass(clazz2);

		if (clazz1URL.equals(clazz2URL)) {
			return true;
		}
		return false;
	}

	public static boolean isSameModule(Class<?> clazz1, Class<?> clazz2) {
		if (isSameURL(clazz1, clazz2)
				&& (clazz1.getClassLoader() == clazz2.getClassLoader())) {
			return true;
		}
		return false;
	}
	
	public static Class<?> loadClassFromJarFile(JarFile jarFile,String className) throws ClassNotFoundException{
		return loadClassFromJarFile(jarFile, className, false);
	}
	
	public static Class<?> loadClassFromJarFile(JarFile file,String className,boolean reslove) throws ClassNotFoundException{
		if(file!=null&&!file.equals(jarFile)){
			jarFile = file;
			jarClassLoader = null;
		}
		if(jarClassLoader == null){
			File f = new File(jarFile.toString());
			try {
				jarClassLoader = new JarClassLoader(new URL[]{f.toURI().toURL()});				
			} catch (MalformedURLException e) {
				e.printStackTrace();
			}
		}
		return jarClassLoader.loadClass(className);
	}

	private static class JarClassLoader extends URLClassLoader {

		private URLClassPath ucp ;

		public JarClassLoader(URL[] urls, ClassLoader parent,
				URLStreamHandlerFactory factory) {
			super(urls, parent, factory);
			ucp = new URLClassPath(urls);
		}

		public JarClassLoader(URL[] urls, ClassLoader parent) {
			super(urls, parent);
			ucp = new URLClassPath(urls);
		}

		public JarClassLoader(URL[] urls) {
			super(urls);
			ucp = new URLClassPath(urls);
		}

		// 构造该类的Class对象
		public Class<?> findClass(String name) throws ClassNotFoundException {
			String path = name;
			int index = name.indexOf(".class");
			if (index < 0) {
				path = name.replace('.', '/').concat(".class");
			} else {
				name = name.substring(0, index).replace("/", ".");
			}
			Class<?> c = findLoadedClass(name);
			if (c != null) {
				return c;
			}

			// ucp.addURL(this.urls[0]);
			Resource res = ucp.getResource(path, false);
			if (res != null) {
				try {
					byte[] bytes = res.getBytes();
					return defineClass(null, bytes, 0, bytes.length);
				} catch (IOException e) {
					throw new ClassNotFoundException(name, e);
				}
			} else {
				throw new ClassNotFoundException(name);
			}
		}

	}

	public static void main(String[] args) {
		
	}
}
